/**
  ******************************************************************************
  * @file    gd32f20cl_eval_exmc_sdram.c 
  * @author  MCU SD
  * @version V1.0.0
  * @date    15-Jul-2015
  * @brief   EXMC write or read SDRAM functions.
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stdio.h"
#include "gd32f20cl_eval_exmc_sdram.h"
#include "systick.h"
/* Private define ------------------------------------------------------------*/
#define SDRAM_TIMEOUT                            ((uint32_t)0x0000FFFF)
#define SDRAM_BANK1_ADDR                         ((uint32_t)0xC0000000)
#define SDRAM_BANK2_ADDR                         ((uint32_t)0xD0000000)

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  Configure EXMC and GPIOs to access the SDRAM.
  * @param  EXMC_Bank: Specify which a SDRAM memory block is written.
  * @retval None
  */
void SDRAM_Init(uint32_t EXMC_Bank)
{  
    GPIO_InitPara             GPIO_InitStructure;
    EXMC_SDRAMInitPara        EXMC_SDRAMInitStructure;
    EXMC_SDRAMTimingInitPara  EXMC_SDRAMTimingInitStructure;
    EXMC_SDRAMCommandPara     EXMC_SDRAMCommandStructure;

    uint32_t tmpr = 0, bank_sdram, bank_select;
    uint32_t timeout = SDRAM_TIMEOUT;

    RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_GPIOB | RCC_APB2PERIPH_GPIOC | RCC_APB2PERIPH_GPIOD |
                               RCC_APB2PERIPH_GPIOE | RCC_APB2PERIPH_GPIOF | RCC_APB2PERIPH_GPIOG , 
                               ENABLE);
    RCC_APB2Periph2Clock_Enable(RCC_APB2PERIPH2_GPIOH , ENABLE);
    RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_AF , ENABLE);
    RCC_AHBPeriphClock_Enable(RCC_AHBPERIPH_EXMC , ENABLE);  


    /* Common GPIO configuration */
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
    
    /* EXMC gpio pin PC0: SDR_NWE remap */
    GPIO_PinRemapConfig2(PCFR6, PCFR6_REMAP_EXMC_SDNWE_PC0, ENABLE);

    /* GPIOC configuration */ 
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_0;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    /* GPIOD configuration */
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_8 | GPIO_PIN_9 |
                                  GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15;

    GPIO_Init(GPIOD, &GPIO_InitStructure);

    /* GPIOE configuration */
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_7  | GPIO_PIN_8 |
                                  GPIO_PIN_9  | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
                                  GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;

    GPIO_Init(GPIOE, &GPIO_InitStructure);

    /* GPIOF configuration */
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_2  | GPIO_PIN_3  |
                                  GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_11 | GPIO_PIN_12 |
                                  GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;      

    GPIO_Init(GPIOF, &GPIO_InitStructure);

    /* GPIOG configuration */
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | 
                                  GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_15;

    GPIO_Init(GPIOG, &GPIO_InitStructure);
    
    /* GPIOH configuration,PH2:SDR_CKE0,PH3:SDR_NE0 */
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_2 | GPIO_PIN_3;

    GPIO_Init(GPIOH, &GPIO_InitStructure);
    
    
    /* Specify which SDRAM to read and write */
    if(EXMC_Bank == EXMC_BANK5_SDRAM)
    {
        bank_sdram = EXMC_BANK5_SDRAM;
        bank_select = EXMC_BANK_SELECT_1;
    }
    else
    {
        bank_sdram = EXMC_BANK6_SDRAM;
        bank_select = EXMC_BANK_SELECT_2;
    }

    /* EXMC SDRAM device initialization sequence --------------------------------*/
    /* Step 1 : Configure SDRAM timing registers --------------------------------*/
    /* LMRD: 3 Clock cycles */
    EXMC_SDRAMTimingInitStructure.EXMC_LoadModeRegisterDelay          = 2;
    /* XSRD: min = 1 Clock cycles */
    EXMC_SDRAMTimingInitStructure.EXMC_ExitSelfRefreshDelay           = 1;
    /* RASD: min=42ns , max=100k (ns) */
    EXMC_SDRAMTimingInitStructure.EXMC_RowAddressSelectDelay          = 3;
    /* ARFD: min=63 */        
    EXMC_SDRAMTimingInitStructure.EXMC_AutoRefreshDelay               = 4;
    /* WRD:  min=2 Clock cycles */
    EXMC_SDRAMTimingInitStructure.EXMC_WriteRecoveryDelay             = 2;
    /* RPD:  min=20ns */
    EXMC_SDRAMTimingInitStructure.EXMC_RowPrechargeDelay              = 2;
    /* RCD:  min=20ns */
    EXMC_SDRAMTimingInitStructure.EXMC_RowToColumnDelay               = 2;
    
    /* Step 1 : Configure SDRAM control registers ---------------------------------*/
    EXMC_SDRAMInitStructure.EXMC_SDRAMBank = bank_sdram;
    EXMC_SDRAMInitStructure.EXMC_ColumnAddressWidth     = EXMC_COLUMN_ADDRESS_WIDTH_9;
    EXMC_SDRAMInitStructure.EXMC_RowAddressWidth        = EXMC_ROW_ADDRESS_WIDTH_13;
    EXMC_SDRAMInitStructure.EXMC_DataWidth              = EXMC_DATA_WIDTH_16;
    EXMC_SDRAMInitStructure.EXMC_InternalBankNumber     = EXMC_INTERNAL_BANK_NUMBER_4;
    EXMC_SDRAMInitStructure.EXMC_CASLatency             = EXMC_CAS_LATENCY_3; 
    EXMC_SDRAMInitStructure.EXMC_WriteProtection        = EXMC_WRITE_PROTECTION_DISABLE;
    EXMC_SDRAMInitStructure.EXMC_SDClockConfig          = EXMC_SDCLK_PERIOD_2;  
    EXMC_SDRAMInitStructure.EXMC_BrustReadSwitch        = EXMC_BRUST_READ_ENABLE;
    EXMC_SDRAMInitStructure.EXMC_PipelineReadDelay      = EXMC_PIPELINE_READ_DELAY_1;
    EXMC_SDRAMInitStructure.EXMC_SDRAMTimingParaStruct  = &EXMC_SDRAMTimingInitStructure;
    /* EXMC SDRAM bank initialization */
    EXMC_SDRAM_Init(&EXMC_SDRAMInitStructure);

    /* Step 3 : Configure CKE high command---------------------------------------*/
    EXMC_SDRAMCommandStructure.EXMC_Command             = EXMC_COMMAND_CKE_HIGH;
    EXMC_SDRAMCommandStructure.EXMC_BankSelect          = bank_select;
    EXMC_SDRAMCommandStructure.EXMC_AutoRefreshNumber   = 1;
    EXMC_SDRAMCommandStructure.EXMC_ModeRegisterContent = 0;
    /* Wait until the SDRAM controller is ready */ 
    while((EXMC_GetBitState(bank_sdram, EXMC_FLAG_READY) != RESET) && (timeout > 0))
    {
        timeout--;
    }
    /* Send the command */
    EXMC_SDRAM_CmdConfig(&EXMC_SDRAMCommandStructure);  

    /* Step 4 : Insert 10 ms delay----------------------------------------------*/
//    USB_OTG_HWP_mDelay (10);
    Delay_1ms(10);

    /* Step 5 : Configure precharge all command----------------------------------*/
    EXMC_SDRAMCommandStructure.EXMC_Command              = EXMC_COMMAND_PRECHARGE;
    EXMC_SDRAMCommandStructure.EXMC_BankSelect           = bank_select;
    EXMC_SDRAMCommandStructure.EXMC_AutoRefreshNumber    = 1;
    EXMC_SDRAMCommandStructure.EXMC_ModeRegisterContent  = 0;
    /* Wait until the SDRAM controller is ready */  
    timeout = SDRAM_TIMEOUT; 
    while((EXMC_GetBitState(bank_sdram, EXMC_FLAG_READY) != RESET) && (timeout > 0))
    {
        timeout--;
    }
    /* Send the command */
    EXMC_SDRAM_CmdConfig(&EXMC_SDRAMCommandStructure);

    /* Step 6 : Configure Auto-Refresh command-----------------------------------*/
    EXMC_SDRAMCommandStructure.EXMC_Command              = EXMC_COMMAND_AUTO_REFRESH;
    EXMC_SDRAMCommandStructure.EXMC_BankSelect           = bank_select;
    EXMC_SDRAMCommandStructure.EXMC_AutoRefreshNumber    = 8;
    EXMC_SDRAMCommandStructure.EXMC_ModeRegisterContent  = 0;
    /* Wait until the SDRAM controller is ready */ 
    timeout = SDRAM_TIMEOUT; 
    while((EXMC_GetBitState(bank_sdram, EXMC_FLAG_READY) != RESET) && (timeout > 0))
    {
        timeout--;
    }
    /* Send the command */
    EXMC_SDRAM_CmdConfig(&EXMC_SDRAMCommandStructure);

    /* Step 7 : Configure load mode register command-----------------------------*/
    /* Program mode register */
    tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1        |
                   SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
                   SDRAM_MODEREG_CAS_LATENCY_3           |
                   SDRAM_MODEREG_OPERATING_MODE_STANDARD |
                   SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;

    EXMC_SDRAMCommandStructure.EXMC_Command              = EXMC_COMMAND_LOAD;
    EXMC_SDRAMCommandStructure.EXMC_BankSelect           = bank_select;
    EXMC_SDRAMCommandStructure.EXMC_AutoRefreshNumber    = 1;
    EXMC_SDRAMCommandStructure.EXMC_ModeRegisterContent  = tmpr;

    /* Wait until the SDRAM controller is ready */ 
    timeout = SDRAM_TIMEOUT; 
    while((EXMC_GetBitState(bank_sdram, EXMC_FLAG_READY) != RESET) && (timeout > 0))
    {
        timeout--;
    }
    /* Send the command */
    EXMC_SDRAM_CmdConfig(&EXMC_SDRAMCommandStructure);

    /* Step 8 : Set the auto-refresh rate counter--------------------------------*/
    /* (7.81 us * Freq) - 20 */
    EXMC_SDRAM_SetRefreshCount(261);

    /* Wait until the SDRAM controller is ready */ 
    timeout = SDRAM_TIMEOUT; 
    while((EXMC_GetBitState(bank_sdram, EXMC_FLAG_READY) != RESET) && (timeout > 0))
    {
        timeout--;
    }
}
/**
  * @brief  Write a Byte buffer(data is 8 bits ) to the EXMC SDRAM memory. 
  * @param  EXMC_Bank : Specify which a SDRAM memory block is written.
  * @param  pBuffer : pointer to buffer. 
  * @param  WriteAddr : SDRAM memory internal address from which the data will be 
  *         written.
  * @param  NumByteToWrite : number of bytes to write. 
  * @retval None
  */
void SDRAM_WriteBuffer_8(uint32_t EXMC_Bank,uint8_t* pBuffer, uint32_t WriteAddr, uint32_t NumByteToWrite)
{
    uint32_t temp_addr;
    
    /* Select the base address according to EXMC_Bank */
    if(EXMC_Bank == EXMC_BANK5_SDRAM)
    {
        temp_addr = SDRAM_BANK1_ADDR;
    }
    else
    {
        temp_addr = SDRAM_BANK2_ADDR;
    }
    
     /* While there is data to write */
    for(; NumByteToWrite != 0; NumByteToWrite--) 
    {
        /* Transfer data to the memory */
        *(uint8_t *) (temp_addr + WriteAddr) = *pBuffer++;

        /* Increment the address*/  
        WriteAddr += 1;
    }
}

/**
  * @brief  Read a block of 8-bit data from the EXMC SDRAM memory.
  * @param  EXMC_Bank : Specify which a SDRAM memory block is written.
  * @param  pBuffer : pointer to the buffer that receives the data read from the 
  *         SDRAM memory.
  * @param  ReadAddr : SDRAM memory internal address to read from.
  * @param  NumByteToRead : number of bytes to read.
  * @retval None
  */
void SDRAM_ReadBuffer_8(uint32_t EXMC_Bank,uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead)
{
    uint32_t temp_addr;
    
    /* Select the base address according to EXMC_Bank */
    if(EXMC_Bank == EXMC_BANK5_SDRAM)
    {
        temp_addr = SDRAM_BANK1_ADDR;
    }
    else
    {
        temp_addr = SDRAM_BANK2_ADDR;
    }
    
    /* While there is data to read */
    for(; NumByteToRead != 0; NumByteToRead--)
    {
        /* Read a byte from the memory */
        *pBuffer++ = *(uint8_t*) (temp_addr + ReadAddr);
    
        /* Increment the address */
        ReadAddr += 1;
    }
}

/**
  * @brief  Write a Half-word buffer(data is 16 bits ) to the EXMC SDRAM memory. 
  * @param  EXMC_Bank : Specify which a SDRAM memory block is written.
  * @param  pBuffer : pointer to buffer. 
  * @param  WriteAddr : SDRAM memory internal address from which the data will be 
  *         written.
  * @param  NumHalfwordToWrite : number of half-words to write. 
  * @retval None
  */
void SDRAM_WriteBuffer_16(uint32_t EXMC_Bank,uint16_t* pBuffer, uint32_t WriteAddr, uint32_t NumHalfwordToWrite)
{
    uint32_t temp_addr;
    
    /* Select the base address according to EXMC_Bank */
    if(EXMC_Bank == EXMC_BANK5_SDRAM)
    {
        temp_addr = SDRAM_BANK1_ADDR;
    }
    else
    {
        temp_addr = SDRAM_BANK2_ADDR;
    }
    
     /* While there is data to write */
    for(; NumHalfwordToWrite != 0; NumHalfwordToWrite--) 
    {
        /* Transfer data to the memory */
        *(uint16_t *) (temp_addr + WriteAddr) = *pBuffer++;

        /* Increment the address*/  
        WriteAddr += 2;
    }
}

/**
  * @brief  Read a block of 16-bit data from the EXMC SDRAM memory.
  * @param  EXMC_Bank : Specify which a SDRAM memory block is written.
  * @param  pBuffer : pointer to the buffer that receives the data read from the 
  *         SRAM memory.
  * @param  ReadAddr : SDRAM memory internal address to read from.
  * @param  NumHalfwordToRead : number of half-words to read.
  * @retval None
  */
void SDRAM_ReadBuffer_16(uint32_t EXMC_Bank,uint16_t* pBuffer, uint32_t ReadAddr, uint32_t NumHalfwordToRead)
{
    uint32_t temp_addr;
    
    /* Select the base address according to EXMC_Bank */
    if(EXMC_Bank == EXMC_BANK5_SDRAM)
    {
        temp_addr = SDRAM_BANK1_ADDR;
    }
    else
    {
        temp_addr = SDRAM_BANK2_ADDR;
    }
    
    /* While there is data to read */
    for(; NumHalfwordToRead != 0; NumHalfwordToRead--)
    {
        /* Read a byte from the memory */
        *pBuffer++ = *(uint16_t*) (temp_addr + ReadAddr);
    
        /* Increment the address */
        ReadAddr += 2;
    }
}

/**
  * @brief  Write a Word buffer(data is 32 bits ) to the EXMC SDRAM memory. 
  * @param  EXMC_Bank : Specify which a SDRAM memory block is written.
  * @param  pBuffer : pointer to buffer. 
  * @param  WriteAddr : SDRAM memory internal address from which the data will be 
  *         written.
  * @param  NumWordToWrite : number of words to write. 
  * @retval None
  */
void SDRAM_WriteBuffer_32(uint32_t EXMC_Bank,uint32_t* pBuffer, uint32_t WriteAddr, uint32_t NumWordToWrite)
{
    uint32_t temp_addr;
    
    /* Select the base address according to EXMC_Bank */
    if(EXMC_Bank == EXMC_BANK5_SDRAM)
    {
        temp_addr = SDRAM_BANK1_ADDR;
    }
    else
    {
        temp_addr = SDRAM_BANK2_ADDR;
    }
    
     /* While there is data to write */
    for(; NumWordToWrite != 0; NumWordToWrite--) 
    {
        /* Transfer data to the memory */
        *(uint32_t *) (temp_addr + WriteAddr) = *pBuffer++;

        /* Increment the address*/  
        WriteAddr += 4;
    }
}

/**
  * @brief  Read a block of 32-bit data from the EXMC SDRAM memory.
  * @param  EXMC_Bank : Specify which a SDRAM memory block is written.
  * @param  pBuffer : pointer to the buffer that receives the data read from the 
  *         SDRAM memory.
  * @param  ReadAddr : SDRAM memory internal address to read from.
  * @param  NumWordToRead : number of words to read.
  * @retval None
  */
void SDRAM_ReadBuffer_32(uint32_t EXMC_Bank,uint32_t* pBuffer, uint32_t ReadAddr, uint32_t NumWordToRead)
{
    uint32_t temp_addr;
    
    /* Select the base address according to EXMC_Bank */
    if(EXMC_Bank == EXMC_BANK5_SDRAM)
    {
        temp_addr = SDRAM_BANK1_ADDR;
    }
    else
    {
        temp_addr = SDRAM_BANK2_ADDR;
    }
    
    /* While there is data to read */
    for(; NumWordToRead != 0; NumWordToRead--)
    {
        /* Read a byte from the memory */
        *pBuffer++ = *(uint32_t*) (temp_addr + ReadAddr);
    
        /* Increment the address */
        ReadAddr += 4;
    }
}

/******************* (C) COPYRIGHT 2015 GIGADEVICE *****END OF FILE****/
